﻿// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) 2007 Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.Office.Tools;

namespace TShooter.TfsWord.AddIn.UIManager
{
    /// <summary>
    /// Collection of UI containers.
    /// </summary>
    /// <typeparam name="TContainer">Type of the UI container.</typeparam>
    /// <typeparam name="TWindow">Type of the Window. E.g. Word Window or Outlook Inspector.</typeparam>
    public sealed class UIContainerCollection<TContainer, TWindow> : Collection<TContainer>
        where TContainer : UIContainerBase<TWindow> 
        where TWindow : class
    {
        #region Fields

        private readonly UIManagerBase<TContainer, TWindow> uiManager;

        #endregion

        #region .ctor

        internal UIContainerCollection(UIManagerBase<TContainer, TWindow> uiManager)
        {
            this.uiManager = uiManager;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Get UIContainer for specified window. Or create a new UIContainer for it.
        /// </summary>
        /// <param name="window">Target window.</param>
        /// <returns>The UIContainer object which is associated with the target window.</returns>
        public TContainer GetContainer(TWindow window)
        {
            int index = IndexOfWindow(window);

            if (index >= 0)
            {
                return this[index];
            }
            
            TContainer container = uiManager.CreateContainer(window);
            Add(container);

            return container;
        }

        #endregion

        #region Methods Overriden from Collection<T>

        protected override void InsertItem(int index, TContainer item)
        {
            if (null == item)
            {
                throw new ArgumentNullException("item");
            }

            // make sure no duplicated windows in the collection.
            int oldIndex = IndexOfWindow(item.Window);
            if (oldIndex >= 0)
            {
                base.RemoveItem(oldIndex);
            }

            base.InsertItem(index, item);
        }

        protected override void SetItem(int index, TContainer item)
        {
            if (null == item)
            {
                throw new ArgumentNullException("item");
            }

            // make sure no duplicated windows in the collection.
            int oldIndex = IndexOfWindow(item.Window);
            if (oldIndex >= 0 && oldIndex != index)
            {
                base.RemoveItem(oldIndex);
            }

            base.SetItem(index, item);
        }

        protected override void RemoveItem(int index)
        {
            if (0 <= index && index < Count)
            {
                TContainer container = this[index];

                var taskPanes = new List<CustomTaskPane>(container.CustomTaskPanes);

                foreach (CustomTaskPane taskPane in taskPanes)
                {
                    uiManager.CustomTaskPanes.Remove(taskPane);
                }
            }

            base.RemoveItem(index);
        }

        protected override void ClearItems()
        {
            for (int i = uiManager.CustomTaskPanes.Count - 1; i >= 0; i--)
            {
                uiManager.CustomTaskPanes.RemoveAt(i);
            }

            base.ClearItems();
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Get the index of container which hosts the specified window.
        /// </summary>
        /// <param name="window">Target window.</param>
        /// <returns>The index of the container. Or -1 if no such container exists in the collection.</returns>
        private int IndexOfWindow(TWindow window)
        {
            for (int i = 0; i < Count; i++)
            {
                TWindow containerWindow = this[i].Window;

                if (Equals(containerWindow, window))
                {
                    return i;
                }
            }

            return -1;
        }

        #endregion
    }
}